import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
public class Billing {
    private static final int SPRING_MONTH = 3; // 春季夏令时开始月份（3月）
    private static final int FALL_MONTH = 11; // 秋季夏令时结束月份（11月）
    private static final int DST_START_WEEK = 2; // 春季夏令时开始周数（第二周）
    private static final int DST_END_WEEK = 1; // 秋季夏令时结束周数（第一周）
    private static final DayOfWeek DST_START_DOW = DayOfWeek.SUNDAY; // 春季夏令时开始星期几（星期日）
    private static final DayOfWeek DST_END_DOW = DayOfWeek.SUNDAY; // 秋季夏令时结束星期几（星期日）
    private static final int DST_START_HOUR = 2; // 春季夏令时开始小时数（2点）
    private static final int DST_END_HOUR = 1; // 秋季夏令时结束小时数（2点）

    // 计算通话时长（秒）
    public static long calculateSeconds(final LocalDateTime startTime, final LocalDateTime endTime) {

        if ((!isDST(startTime)) && isDST(endTime)) {
            //起始时间在不在，终止时间在
            return Duration.between(startTime, endTime).getSeconds() - 3600;
        } else if (isDST(startTime) && (!isDST(endTime))) {

            return Duration.between(startTime, endTime.plusHours(1L)).getSeconds();
        } else {
            return Duration.between(startTime, endTime).getSeconds();
        }
    }

    // 判断时间是否在夏令时期间
    private static boolean isDST(final LocalDateTime dateTime) {
        int year = dateTime.getYear();
        LocalDateTime dstStart = getDSTStartDate(year);
        LocalDateTime dstEnd = getDSTEndDate(year);
        return !dateTime.isBefore(dstStart) && dateTime.isBefore(dstEnd);
    }

    // 获取某年的夏令时开始时间
    private static LocalDateTime getDSTStartDate(final int year) {
        LocalDateTime dateTime = LocalDateTime.of(year, SPRING_MONTH, 1, DST_START_HOUR, 0);
        dateTime = dateTime.withDayOfMonth(1 + (DST_START_WEEK - 1) * 7);
        while (dateTime.getDayOfWeek() != DST_START_DOW) {
            dateTime = dateTime.plusDays(1);
        }
        return dateTime;
    }

    // 获取某年的夏令时结束时间
    private static LocalDateTime getDSTEndDate(final int year) {
        LocalDateTime dateTime = LocalDateTime.of(year, FALL_MONTH, 1, DST_END_HOUR, 59, 59);
        dateTime = dateTime.withDayOfMonth(1 + (DST_END_WEEK - 1) * 7);
        while (dateTime.getDayOfWeek() != DST_END_DOW) {
            dateTime = dateTime.plusDays(1);
        }
        return dateTime;
    }

    // 计算通话费用
    public static BigDecimal calculateFee(final long timeLength) {
        if (timeLength <= 0 || timeLength >= 18000) {
            return BigDecimal.ZERO; // 无效的通话时间
        }

        long minutes = (long) Math.ceil(timeLength / 60.0); // 向上进位到分钟

        if (minutes <= 20) {
            // 不足1分钟按1分钟计算
            minutes = Math.max(minutes, 1);
            return BigDecimal.valueOf(minutes * 0.05);
        } else {
            BigDecimal fee = BigDecimal.valueOf(1); // 前20分钟每分钟0.05美元
            fee = fee.add(BigDecimal.valueOf((minutes - 20) * 0.10)); // 超过20分钟的部分每分钟0.10美元
            return fee;
        }
    }

}
